﻿using System;
using System.Configuration;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace DSFramework
{
    /// <summary>
    /// 实用工具类
    /// </summary>
    public static class UtilitieTools
    {
        #region 运行一个实例

        public static void StartSingle()
        {
            Process[] processes = Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName);
            if (processes.Length > 1)
            {
                System.Environment.Exit(1);
            }
        }

        #endregion

        #region MD5加密 校验

        /// <summary>
        /// 创建哈希字符串适用于任何 MD5 哈希函数 （在任何平台） 上创建 32 个字符的十六进制格式哈希字符串
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string Get32MD5One(string source)
        {
            using (System.Security.Cryptography.MD5 md5Hash = System.Security.Cryptography.MD5.Create())
            {
                byte[] data = md5Hash.ComputeHash(System.Text.Encoding.UTF8.GetBytes(source));
                System.Text.StringBuilder sBuilder = new System.Text.StringBuilder();
                for (int i = 0; i < data.Length; i++)
                {
                    sBuilder.Append(data[i].ToString("x2"));
                }

                string hash = sBuilder.ToString();
                return hash.ToUpper();
            }
        }

        /// <summary>
        /// 获取16位md5加密
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string Get16MD5One(string source)
        {
            using (System.Security.Cryptography.MD5 md5Hash = System.Security.Cryptography.MD5.Create())
            {
                byte[] data = md5Hash.ComputeHash(System.Text.Encoding.UTF8.GetBytes(source));
                //转换成字符串，并取9到25位
                string sBuilder = BitConverter.ToString(data, 4, 8);
                //BitConverter转换出来的字符串会在每个字符中间产生一个分隔符，需要去除掉
                sBuilder = sBuilder.Replace("-", "");
                return sBuilder.ToString().ToUpper();
            }
        }

        //// <summary>
        /// </summary>
        /// <param name="strSource">需要加密的明文</param>
        /// <returns>返回32位加密结果，该结果取32位加密结果的第9位到25位</returns>
        public static string Get32MD5Two(string source)
        {
            System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            //获取密文字节数组
            byte[] bytResult = md5.ComputeHash(System.Text.Encoding.Default.GetBytes(source));
            //转换成字符串，32位
            string strResult = BitConverter.ToString(bytResult);
            //BitConverter转换出来的字符串会在每个字符中间产生一个分隔符，需要去除掉
            strResult = strResult.Replace("-", "");
            return strResult.ToUpper();
        }

        //// <summary>
        /// </summary>
        /// <param name="strSource">需要加密的明文</param>
        /// <returns>返回16位加密结果，该结果取32位加密结果的第9位到25位</returns>
        public static string Get16MD5Two(string source)
        {
            System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            //获取密文字节数组
            byte[] bytResult = md5.ComputeHash(System.Text.Encoding.Default.GetBytes(source));
            //转换成字符串，并取9到25位
            string strResult = BitConverter.ToString(bytResult, 4, 8);
            //BitConverter转换出来的字符串会在每个字符中间产生一个分隔符，需要去除掉
            strResult = strResult.Replace("-", "");
            return strResult.ToUpper();
        }

        #endregion

        #region DES 加密 解密

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="sourceString"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public static string Encrypt_Base64(string sourceString, string key, string iv)
        {
            try
            {
                byte[] btKey = Encoding.UTF8.GetBytes(key);

                byte[] btIV = Encoding.UTF8.GetBytes(iv);

                DESCryptoServiceProvider des = new DESCryptoServiceProvider();

                using (MemoryStream ms = new MemoryStream())
                {
                    byte[] inData = Encoding.UTF8.GetBytes(sourceString);
                    try
                    {
                        using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(btKey, btIV),
                            CryptoStreamMode.Write))
                        {
                            cs.Write(inData, 0, inData.Length);

                            cs.FlushFinalBlock();
                        }

                        return Convert.ToBase64String(ms.ToArray());
                    }
                    catch (Exception e)
                    {
                        return e.ToString();
                    }
                }
            }
            catch
            {
            }

            return "DES加密出错";
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="encryptedString"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public static string Decrypt_Base64(string encryptedString, string key, string iv)
        {
            byte[] btKey = Encoding.UTF8.GetBytes(key);

            byte[] btIV = Encoding.UTF8.GetBytes(iv);

            DESCryptoServiceProvider des = new DESCryptoServiceProvider();

            using (MemoryStream ms = new MemoryStream())
            {
                byte[] inData = Convert.FromBase64String(encryptedString);
                try
                {
                    using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(btKey, btIV),
                        CryptoStreamMode.Write))
                    {
                        cs.Write(inData, 0, inData.Length);

                        cs.FlushFinalBlock();
                    }

                    return Encoding.UTF8.GetString(ms.ToArray());
                }
                catch
                {
                    return encryptedString;
                }
            }
        }

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="sInputString"></param>
        /// <param name="sKey"></param>
        /// <param name="sIV"></param>
        /// <returns></returns>
        public static string Encrypt_Hex(string sInputString, string sKey, string sIV)
        {
            try
            {
                byte[] data = Encoding.UTF8.GetBytes(sInputString);

                DESCryptoServiceProvider DES = new DESCryptoServiceProvider();

                DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);

                DES.IV = ASCIIEncoding.ASCII.GetBytes(sIV);

                ICryptoTransform desencrypt = DES.CreateEncryptor();

                byte[] result = desencrypt.TransformFinalBlock(data, 0, data.Length);

                return BitConverter.ToString(result);
            }
            catch
            {
            }

            return "转换出错！";
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="sInputString"></param>
        /// <param name="sKey"></param>
        /// <param name="sIV"></param>
        /// <returns></returns>
        public static string Decrypt_Hex(string sInputString, string sKey, string sIV)
        {
            try
            {
                string[] sInput = sInputString.Split("-".ToCharArray());

                byte[] data = new byte[sInput.Length];

                for (int i = 0; i < sInput.Length; i++)
                {
                    data[i] = byte.Parse(sInput[i], NumberStyles.HexNumber);
                }

                DESCryptoServiceProvider DES = new DESCryptoServiceProvider();

                DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);

                DES.IV = ASCIIEncoding.ASCII.GetBytes(sIV);

                ICryptoTransform desencrypt = DES.CreateDecryptor();

                byte[] result = desencrypt.TransformFinalBlock(data, 0, data.Length);

                return Encoding.UTF8.GetString(result);
            }
            catch
            {
            }

            return "解密出错！";
        }

        #endregion

        #region 时间

        public static string Year
        {
            get => DateTime.Now.Year.ToString();
        }

        public static string Month
        {
            get => DateTime.Now.Month.ToString();
        }

        public static string Day
        {
            get => DateTime.Now.Day.ToString();
        }

        public static string Time
        {
            get => DateTime.Now.ToLongTimeString().ToString();
        }

        public static string Date
        {
            get => DateTime.Now.ToString();
        }

        #endregion

        #region Log_System

        /// <summary>
        /// 日志类型
        /// </summary>
        public enum LogType
        {
            Info,
            Debug,
            Error,
        }

        /// <summary>
        /// 输出日志
        /// </summary>
        public enum LogOutput
        {
            /// <summary>
            /// 写入所有地方
            /// </summary>
            All,

            /// <summary>
            /// 只写入控制台和文件
            /// </summary>
            ConsoleAndFile,

            /// <summary>
            /// 只写入调试和文件
            /// </summary>
            DebugAndFile,

            ConsoleAndDebug,

            /// <summary>
            /// 只写入控制台
            /// </summary>
            Console,

            /// <summary>
            /// 只写入调试
            /// </summary>
            Debug,

            /// <summary>
            /// 只写入文件
            /// </summary>
            File
        }

        /// <summary>
        /// 是否启用日志调试
        /// </summary>
        public static bool Is_Log = true;

        /// <summary>
        /// 日志路径
        /// </summary>
        public static string LogPath { get; set; } = AppDomain.CurrentDomain.BaseDirectory;

        /// <summary>
        /// 是否启用控制台输出
        /// </summary>
        private static bool Is_Console = false;

        /// <summary>
        /// 是否启用调试输出
        /// </summary>
        private static bool Is_Debug = false;

        /// <summary>
        /// 是否写入文件
        /// </summary>
        private static bool Is_WriteFile = false;

        /// <summary>
        /// 锁定
        /// </summary>
        private static object Lock_log = new object();

        /// <summary>
        /// 写日志文件
        /// </summary>
        /// <param name="msg">要写入的 内容</param>
        /// <param name="errorName"></param>
        /// <param name="logOutput"></param>
        public static void Log(string msg, string errorName,
            LogType logType = LogType.Error, LogOutput logOutput = LogOutput.All)
        {
            if (!Is_Log) return; //是否开启日志

            //日志路径
            string logPath = LogPath + @"log\";
            if (!Directory.Exists(logPath))
            {
                Directory.CreateDirectory(logPath);
            }

            //日志消息
            string lin_msg = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss-ffff}]||[{logType}]||[{errorName}]\r\n{msg}\r\n";

            //存放日志
            string log = $"{logPath}{DateTime.Now:yyyy-MM-dd}.txt";

            lock (Lock_log)
            {
                switch (logOutput)
                {
                    case LogOutput.All:
                        Is_Debug = Is_Console = Is_WriteFile = true;
                        break;
                    case LogOutput.ConsoleAndFile:
                        Is_Debug = false;
                        Is_WriteFile = Is_Console = true;
                        break;
                    case LogOutput.DebugAndFile:
                        Is_Console = false;
                        Is_Debug = Is_WriteFile = true;
                        break;
                    case LogOutput.ConsoleAndDebug:
                        Is_WriteFile = false;
                        Is_Debug = Is_Console = true;
                        break;
                    case LogOutput.Console:
                        Is_Debug = Is_WriteFile = false;
                        Is_Console = true;
                        break;
                    case LogOutput.Debug:
                        Is_Console = Is_WriteFile = false;
                        Is_Debug = true;
                        break;
                    case LogOutput.File:
                        Is_Console = Is_Debug = false;
                        Is_WriteFile = true;
                        break;
                }

                //如果都没有启用，则直接返回
                if (!Is_Console && !Is_WriteFile && !Is_Debug) return;

                if (Is_WriteFile)
                {
                    File.AppendAllText(log, lin_msg, Encoding.UTF8);
                }

                if (Is_Debug)
                {
                    Debug.WriteLine($"{lin_msg}");
                }

                if (Is_Console)
                {
                    switch (logType)
                    {
                        case LogType.Info:
                            Console.ForegroundColor = ConsoleColor.Green;
                            break;
                        case LogType.Debug:
                            Console.ForegroundColor = ConsoleColor.Yellow;
                            break;
                        case LogType.Error:
                            Console.ForegroundColor = ConsoleColor.Red;
                            break;
                    }

                    Console.WriteLine($"{lin_msg}");
                    Console.ForegroundColor = ConsoleColor.White;
                }
            }
        }

        #endregion

        #region 配置文件

        /// <summary>
        /// 获取配置
        /// </summary>
        /// <param name="strKey"></param>
        /// <returns></returns>
        public static string GetAppConfig(string strKey)
        {
            foreach (string key in ConfigurationManager.AppSettings)
            {
                if (key == strKey)
                {
                    return ConfigurationManager.AppSettings[strKey];
                }
            }

            return null;
        }

        /// <summary>
        /// 更新配置
        /// </summary>
        /// <param name="newKey"></param>
        /// <param name="newValue"></param>
        public static void UpdateAppConfig(string newKey, string newValue)
        {
            bool isModified = false;
            foreach (string key in ConfigurationManager.AppSettings)
            {
                if (key == newKey)
                {
                    isModified = true;
                }
            }

            Configuration config =
                ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            if (isModified)
            {
                config.AppSettings.Settings.Remove(newKey);
            }

            config.AppSettings.Settings.Add(newKey, newValue);
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");
        }

        /// <summary>
        /// 获取连接字符串
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        //public static string GetConStr(string str)
        //{
        //    return ConfigurationManager.ConnectionStrings[str].ConnectionString;
        //}

        #endregion

        #region 程序集 = 反射

        /// <summary>
        /// 使用无参方法
        /// </summary>
        /// <param name="type"></param>
        /// <param name="methodName"></param>
        public static void CreateInstance(Type type, string methodName)
        {
            var methodInfo = type.GetMethod(methodName);
            var obj = Activator.CreateInstance(type);
            methodInfo?.Invoke(obj, null);
        }

        public static Assembly GetAssembly<T>()
        {
            System.Reflection.Assembly asm = System.Reflection.Assembly.GetAssembly(typeof(T));
            return asm;
        }

        /// <summary>
        /// 获取所有活动的程序集
        /// </summary>
        /// <returns></returns>
        public static Assembly[] GetAssemblies()
        {
            return AppDomain.CurrentDomain.GetAssemblies();
        }

        #endregion

        #region 通过特性获取所标记的 类、方法、属性

        /// <summary>
        /// 获取所有标记了该特性的类
        /// </summary>
        /// <typeparam name="T">所标记的特性</typeparam>
        /// <returns></returns>
        public static Type[] GetClassTypes<T>()
        {
            //获取该属性所在的程序集
            Assembly asm = Assembly.GetAssembly(typeof(T));

            #region 获取该特性所标记的类

            //获取所有类
            var types = asm.GetExportedTypes();

            //该特性是否在类上标记
            bool IsInClass(Attribute[] o)
            {
                foreach (Attribute a in o)
                {
                    if (a is T) return true;
                }

                return false;
            }

            //获取到所有标记了该特性的类 (T)
            Type[] classTypes = types.Where(o => IsInClass(Attribute.GetCustomAttributes(o, true))).ToArray();

            #endregion

            return classTypes;
        }

        /// <summary>
        /// 获取该特性在该类中所标记的方法
        /// </summary>
        /// <typeparam name="T">所标记的特性</typeparam>
        /// <param name="type">所在的类</param>
        /// <returns></returns>
        public static MethodInfo[] GetMethodInfos<T>(Type type)
        {
            #region 获取该特性在该类中所标记的方法

            //获取所有方法
            var methods = type.GetMethods();

            //该特性是否在方法上标记
            bool IsInMethod(Attribute[] o)
            {
                foreach (Attribute a in o)
                {
                    if (a is T) return true;
                }

                return false;
            }

            //获取到所有标记了该特性的方法
            MethodInfo[] methodTypes = methods.Where(o => IsInMethod(Attribute.GetCustomAttributes(o, true))).ToArray();

            return methodTypes;

            #endregion
        }

        /// <summary>
        /// 获取该特性在该类中所标记的属性
        /// </summary>
        /// <typeparam name="T">所标记的特性</typeparam>
        /// <param name="type">所在的类</param>
        /// <returns></returns>
        public static PropertyInfo[] GetPropertyInfos<T>(Type type)
        {
            #region 获取该特性在该类中所标记的属性

            //获取所有属性
            var propertys = type.GetProperties();

            //该特性是否在属性上标记
            bool IsInProperty(Attribute[] o)
            {
                foreach (Attribute a in o)
                {
                    if (a is T) return true;
                }

                return false;
            }

            //获取到所有标记了该特性的方法
            PropertyInfo[] propertyTypes =
                propertys.Where(o => IsInProperty(Attribute.GetCustomAttributes(o, true))).ToArray();

            return propertyTypes;

            #endregion
        }

        #endregion
    }
}